package pers.xhh.frontapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import pers.xhh.frontapi.common.Constant;
import pers.xhh.frontapi.common.Mi;
import pers.xhh.frontapi.common.ResultCode;
import pers.xhh.frontapi.dao.MiUserDao;
import pers.xhh.frontapi.entity.MiUserEntity;
import pers.xhh.frontapi.entity.to.user.*;
import pers.xhh.frontapi.entity.vo.SocialUser;
import pers.xhh.frontapi.entity.vo.user.AuthVo;
import pers.xhh.frontapi.entity.vo.user.MiUserVo;
import pers.xhh.frontapi.exception.MiException;
import pers.xhh.frontapi.interceptor.AuthenticationInterceptor;
import pers.xhh.frontapi.service.MiUserService;
import pers.xhh.frontapi.util.FileUtil;
import pers.xhh.frontapi.util.HttpRequest;
import pers.xhh.frontapi.util.Md5Utils;
import pers.xhh.frontapi.util.TokenUtils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author wei-xhh
 * @date 2020-11-22
 */
@Service
public class MiUserServiceImpl extends ServiceImpl<MiUserDao, MiUserEntity> implements MiUserService {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public Mi login(MiUserLogin miUserTo) {
        String password = miUserTo.getPassword();
        String username = miUserTo.getUsername();

        // ->查询用户
        String realPwd = Md5Utils.md5(password);
        QueryWrapper<MiUserEntity> eq = new QueryWrapper<MiUserEntity>()
                .eq("username", username)
                .eq("password", realPwd);
        MiUserEntity one = this.getOne(eq);
        if (one == null) {
            return Mi.error(ResultCode.ERROR302.getMessage(), ResultCode.ERROR302.getStatus());
        }

        // ->用户存在,获取token
        String token = TokenUtils.getToken(one);
        MiUserVo miUserVo = new MiUserVo();
        BeanUtils.copyProperties(one, miUserVo);
        miUserVo.setToken(token);

        // ->返回数据
        return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), miUserVo);

    }

    @Transactional
    @Override
    public Mi register(MiUserTo miUserTo) {
        String password = miUserTo.getPassword();
        String username = miUserTo.getUsername();
        String phone = miUserTo.getPhone();
        String code = miUserTo.getCode();

        // ->查询注册用户是否存在
        MiUserEntity have =
                this.getOne(new QueryWrapper<MiUserEntity>().eq("username", username));
        if (have != null) {
            return Mi.error(ResultCode.ERROR306.getMessage(), ResultCode.ERROR306.getStatus());
        }

        // ->验证 验证码
        String redisCode = redisTemplate.opsForValue().get(Constant.USER_AUTH_CODE_KEY + phone);
        if (!StringUtils.isEmpty(redisCode)) {
            // 验证
            if (code.equals(redisCode.split("_")[0])) {
                // 通过删除
                redisTemplate.delete(Constant.USER_AUTH_CODE_KEY + phone);
                // 验证码通过，进行注册
                // ->注册用户
                MiUserEntity miUserEntity = new MiUserEntity();
                miUserEntity.setUsername(username);
                miUserEntity.setNickname(username);
                miUserEntity.setUserTel(phone);
                miUserEntity.setPassword(Md5Utils.md5(password));
                miUserEntity.setUserSex(0);
                miUserEntity.setCreateTime(new Date());
                miUserEntity.setUpdateTime(new Date());
                boolean save = this.save(miUserEntity);
                if (save) {
                    return Mi.ok(ResultCode.SUCCESS1.getMessage(), ResultCode.SUCCESS1.getStatus(), miUserEntity);
                } else {
                    return Mi.error(ResultCode.ERROR305.getMessage(), ResultCode.ERROR305.getStatus());
                }

            } else {
                return Mi.error(ResultCode.ERROR1403.getMessage(), ResultCode.ERROR1403.getStatus());
            }
        } else {
            return Mi.error(ResultCode.ERROR1402.getMessage(), ResultCode.ERROR1402.getStatus());
        }


    }

    @Override
    public Mi getUser() {
        MiUserEntity miUserEntity = AuthenticationInterceptor.threadLocal.get();
        Integer id = miUserEntity.getUserId();
        if (id == null || id <= 0) {
            return Mi.error(ResultCode.ERROR308.getMessage(), ResultCode.ERROR308.getStatus());
        }

        // ->查询
        MiUserEntity byId = this.getById(id);
        if (byId != null) {
            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), byId);
        } else {
            return Mi.error(ResultCode.ERROR310.getMessage(), ResultCode.ERROR310.getStatus());
        }
    }

    @Override
    public Mi putUser(MiUserPutTo miUserPutTo) {
        MiUserEntity loginUser = AuthenticationInterceptor.threadLocal.get();
        Integer id = loginUser.getUserId();
        if (id == null || id <= 0) {
            return Mi.error(ResultCode.ERROR308.getMessage(), ResultCode.ERROR308.getStatus());
        }

        String nickname = miUserPutTo.getNickname();
        String userEmail = miUserPutTo.getUserEmail();
        Integer userSex = miUserPutTo.getUserSex();
        String userQq = miUserPutTo.getUserQq();
        String userTel = miUserPutTo.getUserTel();
        String userHobby = miUserPutTo.getUserHobby();
        String userIntroduce = miUserPutTo.getUserIntroduce();

        MiUserEntity miUserEntity = new MiUserEntity();
        miUserEntity.setUserId(id);
        miUserEntity.setUpdateTime(new Date());
        if (nickname != null && !"".equals(nickname)) {
            miUserEntity.setNickname(nickname);
        }
        if (userEmail != null && !"".equals(userEmail)) {
            miUserEntity.setUserEmail(userEmail);
        }
        if (userSex != null && userSex >= 0) {
            miUserEntity.setUserSex(userSex);
        }
        if (userQq != null && !"".equals(userQq)) {
            miUserEntity.setUserQq(userQq);
        }
        if (userTel != null && !"".equals(userTel)) {
            miUserEntity.setUserTel(userTel);
        }
        if (userHobby != null && !"".equals(userHobby)) {
            miUserEntity.setUserHobby(userHobby);
        }
        if (userIntroduce != null && !"".equals(userIntroduce)) {
            miUserEntity.setUserIntroduce(userIntroduce);
        }
        boolean b = this.updateById(miUserEntity);
        if (b) {
            MiUserPutTo putTo = new MiUserPutTo();
            BeanUtils.copyProperties(miUserEntity, putTo);
            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), putTo);
        } else {
            return Mi.error(ResultCode.ERROR309.getMessage(), ResultCode.ERROR309.getStatus());
        }

    }

    @Override
    public Mi weibo(String code) throws Exception {
        // ->获取code 获取token
        String url = Constant.ACCENT_TOKEN_URI + "?client_id=" + Constant.CLIENT_ID
                + "&client_secret=" + Constant.CLIENT_SECRET + "&grant_type=" + Constant.GRANT_TYPE
                + "&redirect_uri=" + Constant.REDIRECT_URI + "&code=" + code;
        SocialUser socialUser =
                restTemplate.postForObject(url, null, SocialUser.class);


        if (socialUser != null) {
            return this.oauthLogin(socialUser);
        } else {
            return Mi.error(ResultCode.ERROR900.getMessage(), ResultCode.ERROR900.getStatus());
        }
    }

    @Transactional
    @Override
    public Mi oauthLogin(SocialUser socialUser) throws Exception {
        //登录和注册合并逻辑
        String uid = socialUser.getUid();
        //1、判断当前社交用户是否已经登录过系统
        MiUserEntity miUserEntity =
                baseMapper.selectOne(new QueryWrapper<MiUserEntity>().eq("social_uid", uid));
        if (miUserEntity != null) {
            //这个用户已经注册,更新表
            MiUserEntity update = new MiUserEntity();
            update.setUserId(miUserEntity.getUserId());
            update.setExpiresIn(miUserEntity.getExpiresIn());
            update.setAccessToken(socialUser.getAccess_token());
            baseMapper.updateById(update);

            // 获取jwt的token
            String token = TokenUtils.getToken(miUserEntity);
            MiUserVo miUserVo = new MiUserVo();
            BeanUtils.copyProperties(miUserEntity, miUserVo);
            miUserVo.setToken(token);

            // ->返回数据
            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), miUserVo);
        } else {
            //2、没有查到当前社交用户对应的记录，获取信息并注册
            //https://api.weibo.com/2/users/show.json?access_token=2.00hd_XJIIJulxB141dc14c80kkASEC&uid=7469990001
            String url = Constant.USERS_URI + "?access_token=" +
                    socialUser.getAccess_token() + "&uid=" + uid;
            String forObject = restTemplate.
                    getForObject(url, String.class);

            //查询成功
            ObjectMapper objectMapper = new ObjectMapper();
            Map map = objectMapper.readValue(forObject, Map.class);
            // 昵称
            String name = (String) map.get("name");
            // 性别
            String gender = (String) map.get("gender");
            // 头像地址 map.get("name") profile_image_url
            String avatarUrl = (String) map.get("profile_image_url");
            // 男为1
            int genderInt = 1;
            if ("w".equals(gender)) {
                genderInt = 0;
            }
            MiUserEntity newUserEntity = new MiUserEntity();
            // 以wb_开头
            newUserEntity.setUsername("wb_" + name);
            newUserEntity.setNickname(name);
            newUserEntity.setPassword(Md5Utils.md5(uid));
            newUserEntity.setSocialUid(socialUser.getUid());
            newUserEntity.setUserSex(genderInt);
            newUserEntity.setExpiresIn(String.valueOf(socialUser.getExpires_in()));
            newUserEntity.setAvatarUrl(avatarUrl);
            newUserEntity.setAccessToken(socialUser.getAccess_token());
            newUserEntity.setUpdateTime(new Date());
            newUserEntity.setCreateTime(new Date());


            // ->保存
            boolean save = this.save(newUserEntity);
            if (save) {
                MiUserVo miUserVo = new MiUserVo();
                BeanUtils.copyProperties(newUserEntity, miUserVo);

                // 获取jwt的token
                String token = TokenUtils.getToken(newUserEntity);
                miUserVo.setToken(token);

                // ->返回数据
                return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), miUserVo);
            } else {
                return Mi.error(ResultCode.ERROR305.getMessage(), ResultCode.ERROR305.getStatus());
            }
        }
    }

    @Override
    public Mi updatePassword(UserPwd userPwd) {
        String oldPwd = userPwd.getOldPwd();
        String password = userPwd.getPassword();
        // 校验旧密码
        boolean b1 = this.testPwd(oldPwd);
        if(b1){
            MiUserEntity miUserEntity = AuthenticationInterceptor.threadLocal.get();
            miUserEntity.setPassword(Md5Utils.md5(password));
            boolean b = this.updateById(miUserEntity);
            if (b) {
                return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), "修改密码成功！");
            } else {
                return Mi.error(ResultCode.ERROR313.getMessage(), ResultCode.ERROR313.getStatus());
            }
        } else {
            return Mi.error(ResultCode.ERROR315.getMessage(), ResultCode.ERROR315.getStatus());
        }
    }

    @Transactional
    @Override
    public Mi uploadAvatar(MultipartFile file) throws IOException {
        MiUserEntity miUserEntity = AuthenticationInterceptor.threadLocal.get();
        String pathName = System.getProperty("catalina.home") + "/webapps/sharePath/avatar/";
        String fileName = UUID.randomUUID().toString().replace("-", "");
        String name = fileName + ".png";
        boolean b = FileUtil.writeFile(file.getInputStream(), pathName + name);
        if (b) {
            // 保存
            miUserEntity.setAvatarUrl("avatar" + File.separator + name);
            boolean b1 = this.updateById(miUserEntity);
            if (b1) {
                Map<String, Object> map = new HashMap<>();
                map.put("path", "avatar" + File.separator + name);
                return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), map);
            } else {
                throw new MiException(ResultCode.ERROR314.getStatus(), ResultCode.ERROR314.getMessage());
            }
        }
        throw new MiException(ResultCode.ERROR314.getStatus(), ResultCode.ERROR314.getMessage());
    }

    @Override
    public boolean testPwd(String password) {
        MiUserEntity miUserEntity = AuthenticationInterceptor.threadLocal.get();
        String oldPwd = miUserEntity.getPassword();
        boolean test = false;
        String newPwd = Md5Utils.md5(password);
        if (newPwd.equals(oldPwd)) {
            test = true;
        }
        return test;
    }

    @Override
    public Mi auth(AuthTo authTo) throws UnsupportedEncodingException, JsonProcessingException {
        String phone = authTo.getPhone();
        String redisCode = redisTemplate.opsForValue().get(Constant.USER_AUTH_CODE_KEY + phone);
        // 1,不为空时间验证
        if (!StringUtils.isEmpty(redisCode)) {
            long l = Long.parseLong(redisCode.split("_")[1]);
            if ((System.currentTimeMillis() - l) < 60000) {
                //60秒内不能再发
                return Mi.error(ResultCode.ERROR1400.getMessage(), ResultCode.ERROR1400.getStatus());
            }
        }
        // 2、验证码的再次校验，redis, 存key-phone value-code 10分钟有效
        String code = String.format("%04d",new Random().nextInt(9999));
        redisTemplate.opsForValue()
                .set(Constant.USER_AUTH_CODE_KEY + phone, code + "_" + System.currentTimeMillis(), 10, TimeUnit.MINUTES);

        // 3. 发送短信
        String authCode = Constant.APP_CODE;
        String content = URLEncoder.encode("【云商城通知】您的验证码是" + code + "。如非本人操作，请忽略本短信", "utf-8");
        String param = "content=" + content + "&mobile=" + phone;
        String s = HttpRequest.sendGet(Constant.AUTH_URL, param, authCode);
        ObjectMapper objectMapper = new ObjectMapper();
        AuthVo authVo = objectMapper.readValue(s, AuthVo.class);

        return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), authVo);
    }

    @Override
    public Mi findPwd(UserFindPwd userFindPwd) {
        String phone = userFindPwd.getPhone();
        String newPwd = userFindPwd.getNewPwd();
        MiUserEntity miUserEntity = AuthenticationInterceptor.threadLocal.get();

        String userTel = miUserEntity.getUserTel();
        if(!userTel.equals(phone)){
            return Mi.error(ResultCode.ERROR316.getMessage(), ResultCode.ERROR316.getStatus());
        }
        miUserEntity.setPassword(Md5Utils.md5(newPwd));
        boolean b = this.updateById(miUserEntity);
        if(b){
            return Mi.ok(ResultCode.SUCCESS.getMessage(), ResultCode.SUCCESS.getStatus(), "找回密码成功！");
        }
        return Mi.error(ResultCode.ERROR317.getMessage(), ResultCode.ERROR317.getStatus());
    }
}
